package com.inspur.edp.bef.bemanager.service;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityErrorCodeEnum;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityException;
import com.inspur.edp.bef.bizentity.json.element.BizElementDeserializer;
import com.inspur.edp.bef.bizentity.json.element.BizElementSerializer;
import com.inspur.edp.bef.bizentity.util.UpdateBeElementUtil;
import com.inspur.edp.bef.bizentity.util.UpdateBeVariableUtil;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.json.Variable.CommonVariableDeserializer;
import com.inspur.edp.cef.designtime.api.json.Variable.CommonVariableSerializer;
import com.inspur.edp.cef.designtime.api.variable.CommonVariable;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import lombok.var;

import org.springframework.util.StringUtils;

public class UpdateElementCollectionService {
    private java.util.HashMap<String, GspMetadata> metadataDic = new java.util.HashMap<String, GspMetadata>();
    private MetadataService lcmDtService;

    private MetadataService getLcmDtService() {
        if (lcmDtService == null)
            lcmDtService = SpringBeanUtils.getBean(MetadataService.class);
        return lcmDtService;

    }

    private static String ERRORCODE = "UpdateElementService";


    public static UpdateElementCollectionService getInstance() {
        return new UpdateElementCollectionService();
    }

    ///#region 批量更新

    /**
     * 批量更新udt字段
     *
     * @param elements
     */
    public void handleUdtElements(String path, java.util.ArrayList<IGspCommonElement> elements) {
        if (elements == null || elements.isEmpty()) {
            return;
        }
        for (IGspCommonElement ele : elements) {
            if (!ele.getIsUdt()) {
                continue;
            }
            GspMetadata refUdtMetadata = getRefMetadata(path, ele.getUdtID(), "UDT");
            UpdateBeElementUtil util = new UpdateBeElementUtil();
            util.updateElementWithRefUdt((GspBizEntityElement) ele, (UnifiedDataTypeDef) refUdtMetadata.getContent(), false);
        }
    }

    /**
     * 批量更新关联字段
     *
     * @param elements
     */
    public void handleRefElements(String path, java.util.ArrayList<IGspCommonElement> elements) {
        if (elements == null || elements.isEmpty()) {
            return;
        }
        for (IGspCommonElement element : elements) {
            if (!element.getHasAssociation()) {
                continue;
            }
            for (GspAssociation asso : element.getChildAssociations()) {
                setAssoModelInfo(path, asso);
            }
        }
    }

    /**
     * 根据选中的udt元数据,更新多值udt字段信息
     * 更新ChildElements,Mapping
     * 说明：若为字段上选择udt，所有属性带出；若为加载更新，则仅更新使用方式为【约束】的属性。
     *
     * @return 更新后字段的json序列化
     */
    public String updateElementWithRefUdt(String refUdtId, String path, String udtElementJson, boolean isFirstChoose) {
        GspMetadata refUdtMetadata = getRefMetadata(path, refUdtId, "UDT");
        Object tempVar;
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();

        module.addDeserializer(IGspCommonField.class, new BizElementDeserializer());
        module.addSerializer(IGspCommonField.class, new BizElementSerializer());
        mapper.registerModule(module);
        try {
            tempVar = mapper.readValue(udtElementJson, GspBizEntityElement.class);

        } catch (JsonProcessingException e) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_JSON_0001, e, "GspBizEntityElement");
        }

        var element = (GspBizEntityElement) ((tempVar instanceof GspBizEntityElement) ? tempVar : null);
        IMetadataContent content = refUdtMetadata.getContent();
        if (content instanceof UnifiedDataTypeDef) {
            UpdateBeElementUtil util = new UpdateBeElementUtil();
            util.updateElementWithRefUdt(element, (UnifiedDataTypeDef) content, isFirstChoose);
        } else {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0062);
        }

        String eleJson = null;
        try {
            eleJson = mapper.writeValueAsString(tempVar);
        } catch (JsonProcessingException e) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_JSON_0004, e, "GspBizEntityElement");
        }
        return eleJson;
    }

    public String updateVariableWithRefUdt(String refUdtId, String path, String udtElementJson, boolean isFirstChoose) {
        GspMetadata refUdtMetadata = getRefMetadata(path, refUdtId, "UDT");
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(IGspCommonField.class, new CommonVariableDeserializer());
        module.addSerializer(IGspCommonField.class, new CommonVariableSerializer());
        mapper.registerModule(module);
        Object tempVar2;
        try {
            tempVar2 = mapper.readValue(udtElementJson, IGspCommonField.class);
        } catch (JsonProcessingException e) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_JSON_0001, e, "CommonVariable");
        }

        var element = (CommonVariable) ((tempVar2 instanceof CommonVariable) ? tempVar2 : null);
        IMetadataContent content = refUdtMetadata.getContent();
        if (content instanceof UnifiedDataTypeDef) {
            UpdateBeVariableUtil util = new UpdateBeVariableUtil();
            util.updateElementWithRefUdt(element, (UnifiedDataTypeDef) content, isFirstChoose);
        } else {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0062);
        }

        String eleJson = null;
        try {
            eleJson = mapper.writeValueAsString(element);
        } catch (JsonProcessingException e) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_JSON_0004, e, "CommonVariable");
        }
        return eleJson;
    }

    ///#endregion


    ///#region 选择关联时处理

    /**
     * 若关联为选择udt带出，则带出字段标签="{当前字段标签}_{udt带出字段标签}"
     *
     * @param element
     */
    public void updateFieldWithAsso(String path, IGspCommonField element) {
        if (!element.getHasAssociation()) {
            return;
        }
        for (GspAssociation asso : element.getChildAssociations()) {
            setAssoModelInfo(path, asso);
            handleUdtRefField(asso, element.getLabelID());
        }
    }

    ///#endregion

    ///#endregion


    ///#region 私有方法

    /**
     * udt关联带出字段，标签需处理
     *
     * @param asso
     * @param prefix
     */
    private void handleUdtRefField(GspAssociation asso, String prefix) {

        for (var refEle : asso.getRefElementCollection()) {
            if (!refEle.getIsUdt()) {
                continue;
            }

            for (var childEle : refEle.getChildElements()) {
                childEle.setLabelID(String.format(prefix, "_", childEle.getLabelID()));
            }
        }
    }

    /**
     * 赋值AssoModelInfo
     * 1.首次选择关联时调用赋值；
     * 2.打开设计器时需调用更新；
     *
     * @param asso
     */
    private void setAssoModelInfo(String path, GspAssociation asso) {

        GspBusinessEntity refModel = (GspBusinessEntity) ((getRefMetadata(path, asso.getRefModelID(), "BE").getContent() instanceof GspBusinessEntity) ? getRefMetadata(path, asso.getRefModelID(), "BE").getContent() : null);
        asso.getAssoModelInfo().setMainObjCode(refModel.getMainObject().getCode());
        asso.getAssoModelInfo().setModelConfigId(refModel.getDotnetGeneratedConfigID());
    }

    private GspMetadata getRefMetadata(String path, String id, String metadataType) {
        if (metadataDic.containsKey(id)) {
            return metadataDic.get(id);
        }
        GspMetadata metadata = StringUtils.isEmpty(path)
            ? SpringBeanUtils.getBean(RefCommonService.class).getRefMetadata(id)
            : getLcmDtService().getRefMetadata(path, id);
        if (metadata.getContent() == null) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0063, id, metadataType);
        }
        metadataDic.put(id, metadata);
        return metadata;
    }

    ///#endregion
}